﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Globalization;
using SoftwareConsulting.BI11.NumericalMethods.Geometry;
using SoftwareConsulting.BI11.Studio.InternalServices;
using SoftwareConsulting.BI11.Studio.Core.Project;
using SoftwareConsulting.BI11.Studio.Core.Project.Metadata;
using SoftwareConsulting.BI11.Studio.UI.ProjectExplorer.Extensions;
using SoftwareConsulting.BI11.Studio.UI.Properties;
using SoftwareConsulting.BI11.NumericalMethods;
using SoftwareConsulting.BI11.Studio.DataTransfer;
using SoftwareConsulting.BI11.Controls.Metadata;

namespace SoftwareConsulting.BI11.Studio.UI.ProjectExplorer.ClassificationProblems
{        
    /// <summary>
    /// Класс формы настройки и запуска Задачи классификации с обучением
    /// </summary>
    public partial class ClassificationProblemWithTrainingRunDialog : RestorableForm
    {        
        private IClassificationProblemWithTraining _problem; //задача классификации
        private ProjectDescriptor _projectLink; //связь с проектом
        private ProjectExplorerForm _projectExplorer; //связь с Обозревателем Проекта
        private bool _isInitialized; //флаг проинициализированного диалога
        private List<MetadataObjectDescriptor> _indicators; //закэшированный список дескрипторов показателей репозитория
        private List<MetadataObjectDescriptor> _tables; //закэшированный список дескрипторов таблиц репозитория
        private List<ObjectOutputArgs> _outputInfo; //информация, собранная в результате вывода
        private List<int> _outputClassCorrect; //массив значений истинных классов объектов (Constants.NullInteger - неизвестно)
        private int _outputPage;//текущая страница вывода
        private bool _inManualTraining; //флаг нахождения в состоянии ручного обучения
        private bool _bindingChanged; //флаг изменения привязок к таблицам

        /// <summary>
        /// Инициализирует диалог
        /// </summary>
        private void Initialize()
        {
            _isInitialized = false;            
            this.SetObjectViewerCaption(Text, _problem.ToString());
            this.Icon = MetadataObjectKind.ClassificationProblem.GetIcon();
            _outputInfo = new List<ObjectOutputArgs>();
            _outputClassCorrect = new List<int>();
            _outputPage = -1;
            MethodBox.SelectedIndex = (int)_problem.Method - 1;
            ManualTrainingCheck.Checked = _problem.ManualTraining;
            ManualInputCheck.Checked = _problem.ManualInput;
            ManualOutputCheck.Checked = _problem.ManualOutput;
            var classesNames = ClassesNamesBox.Properties.Items;
            var attributesNames = AttributesNamesBox.Properties.Items;
            _tables = new List<MetadataObjectDescriptor>();
            foreach (MetadataObjectDescriptor table in _projectLink.RepositoryLink.WalkObjects(MetadataObjectKind.Table))
            {
                _tables.Add(table);
            }
            _indicators = new List<MetadataObjectDescriptor>();            
            classesNames.Clear();
            attributesNames.Clear();
            classesNames.Add(Constants.NullNotDefinedString);
            attributesNames.Add(Constants.NullNotDefinedString);            
            foreach (MetadataObjectDescriptor indicator in _projectLink.RepositoryLink.WalkObjects(MetadataObjectKind.Indicator))
            {
                classesNames.Add(indicator.ToString());
                attributesNames.Add(indicator.ToString());
                _indicators.Add(indicator);
                if ((_problem.ClassesNames != null) && (_problem.ClassesNames.Id == indicator.Id))
                {
                    ClassesNamesBox.SelectedIndex = _indicators.Count;
                }
                if ((_problem.AttributesNames != null) && (_problem.AttributesNames.Id == indicator.Id))
                {
                    AttributesNamesBox.SelectedIndex = _indicators.Count;
                }
            }
            if (ClassesNamesBox.SelectedIndex < 0)
                ClassesNamesBox.SelectedIndex = 0;
            if (AttributesNamesBox.SelectedIndex < 0)
                AttributesNamesBox.SelectedIndex = 0;
            EMaximumDifferenceBox.Text = _problem.EMaximumDifference.ToString(CultureInfo.CurrentUICulture);
            RefreshTrainingCount();
            OutputMoveTo(1);
            bool withHelp = _projectExplorer.SimpleMode;
            MethodsTipBox.Closed = !withHelp;
            _bindingChanged = false;
            _isInitialized = true;
        }

        /// <summary>
        /// Обновляет информацию о количестве объектов, участвовавших в обучении
        /// </summary>
        private void RefreshTrainingCount()
        {
            TrainingCountLabel.Text = string.Format(Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_TRAININGCOUNT, _problem.TrainingCacheCount);            
        }

        /// <summary>
        /// Обрабатывает смену метода классификации
        /// </summary>
        private void ProcessMethodChange()
        {
            if (_isInitialized)
                _problem.Method = (ClassificationProblemMethod)MethodBox.SelectedIndex + 1;            
            if (_problem.Method == ClassificationProblemMethod.ModifiedClassificator)
            {
                DistanceMethod distanceMethod = _problem.DistanceMethod;
                if (distanceMethod == DistanceMethod.None)
                    distanceMethod = DistanceMethod.Euclid;
                DistanceMethodBox.SelectedIndex = (int)distanceMethod - 1;
                DistanceMethodBox.Enabled = true;
                EMaximumDifferenceBox.Visible = true;
                EMaximumDifferenceLabel.Visible = true;                
            }
            else
            {
                DistanceMethodBox.Text = string.Empty;
                DistanceMethodBox.Enabled = false;
                SetInfoButton.Text = string.Format("{0}...", Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_SETATTRIBUTESINFO_GROUPSANDDIFFERENCE);
                SetInfoButton.Visible = true;
                EMaximumDifferenceLabel.Visible = false;
                EMaximumDifferenceBox.Visible = false;
            }
        }

        /// <summary>
        /// Обрабатывает смену метода нахождения расстояний
        /// </summary>
        private void ProcessDistanceMethodChange()
        {
            if (_isInitialized)
            {
                if (!string.IsNullOrEmpty(DistanceMethodBox.Text))
                {
                    DistanceMethod newMethod = (DistanceMethod)DistanceMethodBox.SelectedIndex + 1;
                    if (newMethod != _problem.DistanceMethod)
                    {
                        _problem.DistanceMethod = newMethod;                        
                    }
                }
            }
            if (_problem.DistanceMethod == DistanceMethod.EstimatedEuclid)
            {
                SetInfoButton.Text = string.Format("{0}...", Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_SETATTRIBUTESINFO_WEIGHTS);
                SetInfoButton.Visible = true;
            }
            else
                SetInfoButton.Visible = false;
        }

        /// <summary>
        /// Обрабатывает событие вывода
        /// </summary>
        /// <param name="args"></param>        
        private void OutputEvent(ObjectOutputArgs args)
        {
            if (ClassificationTabs.SelectedTabPage != ResultsTab)            
                ClassificationTabs.SelectedTabPage = ResultsTab;
            ResultBuildProgressBar.Visible = true;
            _outputInfo.Add(args);
            _outputClassCorrect.Add(Constants.NullInteger);            
            bindingNavigatorCountItem.Text = string.Format(Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_OUTPUTPAGE, _outputInfo.Count);
            OutputMoveTo(1);
            ProcessOutputPageChange();
        }

        /// <summary>
        /// Обрабатывает событие ручного ввода
        /// </summary>
        /// <param name="args"></param>
        /// <returns>true - пользователь будет еще вводить, false - не требует</returns>
        private bool ManualInputEvent(ref ObjectManualInputArgs args)
        {
            ClassificationProblemWithTrainingManualInputDialog manualInputDialog = new ClassificationProblemWithTrainingManualInputDialog(_problem, args);
            return manualInputDialog.ShowDialog(this) == DialogResult.OK;
        }

        /// <summary>
        /// Выполняет классификацию
        /// </summary>
        private void Execute()
        {            
            if (!CheckBindingChanged())
                return;
            if (!CheckIndicators())
                return;
            bool needTrain = true;
            try
            {
                needTrain = _problem.CheckNeedTrain();
            }
            catch (BIClassificationProblemWithTrainingTrainingClassFieldNotDefinedException ex)
            {
                GeneralMethods.ShowUserError(ex.Message);
                return;
            }
            if (needTrain)
            {
                if (GeneralMethods.ShowWarning(Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_TRAIN_NEED, MessageBoxButtons.YesNo) == DialogResult.No)
                    return;
            }
            RunButton.Enabled = false;
            if (_problem.ManualTraining)
            {
                _problem.ManualTrainingEvent += ManualTrainingEvent;
            }
            if (_problem.ManualInput)
            {
                _problem.ManualInputEvent += ManualInputEvent;
            }
            _outputInfo = new List<ObjectOutputArgs>();
            _outputClassCorrect = new List<int>();
            _outputPage = -1;
            _problem.OutputEvent += OutputEvent;
            try
            {
                _problem.Solve();
            }
            catch (BIClassificationProblemException ex)
            {
                GeneralMethods.ShowUserError(ex.Message);
                return;
            }
            catch (BIGeometryImpossibleCalculateDistanceException ex)
            {
                //ни указали значения ни у одного из признаков
                Assert.FailIfNot(!_problem.ManualTraining || !_problem.ManualInput, Assert.Id.Assert00313);//в случае ручного обучения должно было по любому на уровне ядра метаданных отловиться
                GeneralMethods.ShowUserError(ex.Message);
                return;
            }
            finally
            {
                _problem.ManualTrainingEvent -= ManualTrainingEvent;
                _problem.ManualInputEvent -= ManualInputEvent;
                _problem.OutputEvent -= OutputEvent;
                RunButton.Enabled = true;
                ResultBuildProgressBar.Visible = false;
                RefreshTrainingCount();
            }
            GeneralMethods.ShowInformation(Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_EXECUTIONEND);            
            if (ClassificationTabs.SelectedTabPage != ResultsTab)
                ClassificationTabs.SelectedTabPage = ResultsTab;
        }

        /// <summary>
        /// Обрабатывает событие ручного обучения задачи
        /// </summary>
        /// <param name="args"></param>
        /// <returns>true - пользователь будет еще обучать, false - не требует</returns>
        private bool ManualTrainingEvent(ref ObjectManualInputArgs args)
        {
            if (_inManualTraining)
            {
                args.ObjectInfo = null;
                return false; //иначе из ОК в editTrainingDialog опять попадем сюда, а не разберем результат диалога
            }
            _inManualTraining = true;
            while (true)
            {
                ClassificationProblemWithTrainingManualTrainingDialog manualTrainingDialog = new ClassificationProblemWithTrainingManualTrainingDialog(_problem, args);
                bool result = false;
                switch (manualTrainingDialog.ShowDialog(this))
                {
                    case DialogResult.OK:
                        result = true;
                        break;
                    case DialogResult.Cancel:
                        result = false;
                        break;
                    case DialogResult.Retry:                        
                        ClassificationProblemWithTrainingEditTrainingDialog editTrainingDialog = new ClassificationProblemWithTrainingEditTrainingDialog(_problem, _projectExplorer);                        
                        if (editTrainingDialog.ShowDialog(this) == DialogResult.OK)
                        {
                            args.ObjectInfo = null;
                            result = false;
                            break;
                        }
                        continue;
                    default:
                        Assert.Fail(Assert.Id.Assert00311);
                        result = false;
                        break;
                }
                _inManualTraining = false;
                return result;
            }            
        }        

        /// <summary>
        /// Вызывает диалог редактирования/удаления обучающей выборки
        /// </summary>
        private void EditTrain()
        {
            ClassificationProblemWithTrainingEditTrainingDialog dialog = new ClassificationProblemWithTrainingEditTrainingDialog(_problem, _projectExplorer);
            dialog.ShowDialog();
            RefreshTrainingCount();
        }

        /// <summary>
        /// Выполняет обучение задачи классификации
        /// </summary>
        private void Train()
        {
            if (!CheckBindingChanged())
                return;
            if (!CheckIndicators())
                return;            
            bool needTrain = true;
            try
            {
                needTrain = _problem.CheckNeedTrain();
            }
            catch (BIClassificationProblemWithTrainingTrainingClassFieldNotDefinedException ex)
            {
                GeneralMethods.ShowUserError(ex.Message);
                return;
            }
            if (needTrain && (_problem.TrainingCacheCount > 0))
            {
                if (GeneralMethods.ShowWarning(Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_TRAIN_NEED, MessageBoxButtons.YesNo) == DialogResult.No)
                    return;
            }                                            
            TrainButton.Enabled = false;
            if (_problem.ManualTraining)
            {
                _problem.ManualTrainingEvent += ManualTrainingEvent;
            }
            try
            {
                _problem.Train();
            }
            catch (BIClassificationProblemException ex)
            {
                GeneralMethods.ShowUserError(ex.Message);
                return;
            }
            catch (BIGeometryImpossibleCalculateDistanceException ex)
            {
                //ни указали значения ни у одного из признаков
                Assert.FailIfNot(!_problem.ManualTraining || !_problem.ManualInput, Assert.Id.Assert00309);//в случае ручного обучения и ввода должно было по любому на уровне ядра метаданных отловиться
                GeneralMethods.ShowUserError(ex.Message);
                return;
            }
            finally
            {
                _problem.ManualTrainingEvent -= ManualTrainingEvent;
                TrainButton.Enabled = true;
            }
            RefreshTrainingCount();
        }

        /// <summary>
        /// Обрабатывает смену режима ручного обучения
        /// </summary>
        private void ProcessManualTrainingChange()
        {
            if (_isInitialized)
                _problem.ManualTraining = ManualTrainingCheck.Checked;
            if (BindingBox.SelectedIndex == 0)
            {
                RefreshBindingTables();
            }
        }

        /// <summary>
        /// Обрабатывает смену режима ручного ввода
        /// </summary>
        private void ProcessManualInputChange()
        {
            if (_isInitialized)
                _problem.ManualInput = ManualInputCheck.Checked;
            if (BindingBox.SelectedIndex == 1)
            {
                RefreshBindingTables();
            }
        }

        /// <summary>
        /// Обрабатывает смену режима ручного вывода
        /// </summary>
        private void ProcessManualOutputChange()
        {
            if (_isInitialized)
                _problem.ManualOutput = ManualOutputCheck.Checked;
            if (BindingBox.SelectedIndex == 2)
            {
                RefreshBindingTables();
            }
            OutputTablesTab.PageVisible = !_problem.ManualOutput;
        }

        /// <summary>
        /// Обрабатывает смену имен классов
        /// </summary>
        private void ProcessClassesNamesChange()
        {
            if (_isInitialized)
            {
                int index = ClassesNamesBox.SelectedIndex;
                IIndicator indicator = index == 0 ? null : _indicators[index - 1].Bind() as IIndicator;
                try
                {
                    _problem.SetClassesNames(indicator);
                }
                catch (BIClassificationProblemIndicatorNotDefinedException ex)
                {
                    GeneralMethods.ShowUserError(ex.Message);
                    return;
                }
                RefreshBindingTables();
            }
        }

        /// <summary>
        /// Заполняет указанный комбобокс всеми таблицами
        /// </summary>
        /// <param name="combo"></param>
        private void FillTables(DataGridViewComboBoxCell combo)
        {
            var items = combo.Items;
            items.Clear();
            items.Add(Constants.NullNotDefinedString);
            for (int i=0;i<_tables.Count;i++)
            {
                items.Add(_tables[i].ToString());
            }            
        }

        /// <summary>
        /// Обрабатывает сменя значения ячейки грида привязок
        /// </summary>
        /// <param name="rowIndex"></param>
        /// <param name="colIndex"></param>
        private void ProcessBindingGridCellValueChange(int rowIndex, int colIndex)
        {
            if (rowIndex == -1)
                return; //заголовочные строки
            if (colIndex == 1)
            {
                //изменили таблицу, значит надо переподтянуть доступные поля таблицы                
                var row = BindingGrid.Rows[rowIndex];
                var tableCombo = row.Cells[colIndex] as DataGridViewComboBoxCell;
                int tableIndex = tableCombo.Items.IndexOf(tableCombo.Value) - 1;//минус 1, т.к. первая строка - "не выбрано"
                var fieldCombo = row.Cells[colIndex + 1] as DataGridViewComboBoxCell;
                fieldCombo.Value = null;
                fieldCombo.Items.Clear();
                fieldCombo.Items.Add(Constants.NullNotDefinedString);
                if (tableIndex >= 0)
                {
                    //выбрана реальная таблица
                    ITable table = _tables[tableIndex].Bind() as ITable;
                    ///подставляем только поля 
                    /// - численного типа для признаков
                    /// - строкового типа для класса и пояснительной надписи
                    bool waitString = (BindingGridRowType)row.Tag != BindingGridRowType.Attribute;
                    foreach (string columnName in table.GetColumnNames())
                    {
                        Type type = table.GetColumnProperties(columnName).ColumnType;
                        if (waitString && (type == typeof(string)) 
                            || !waitString && ((type == typeof(int)) || (type == typeof(double))))
                        {
                            fieldCombo.Items.Add(columnName);
                        }
                    }
                }
                fieldCombo.Value = Constants.NullNotDefinedString;
                _bindingChanged = true;
            }
        }

        /// <summary>
        /// Проверяет наличие заданных показателей имен классов и имен признаков
        /// </summary>
        /// <returns>true - заданы, false - не задан хотя бы один из них</returns>
        private bool CheckIndicators()
        {
            return CheckIndicators(false);
        }

        /// <summary>
        /// Проверяет наличие заданных показателей имен классов и имен признаков
        /// </summary>
        /// <returns>true - заданы, false - не задан хотя бы один из них</returns>
        private bool CheckIndicators(bool silent)
        {
            if (_problem.ClassesNames == null)
            {
                if (!silent)
                    GeneralMethods.ShowWarning(Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_INDICATORNOTDEFINED_CLASSES);
                return false;
            }
            if (_problem.AttributesNames == null)
            {
                if (!silent)
                    GeneralMethods.ShowWarning(Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_INDICATORNOTDEFINED_ATTRIBUTES);
                return false;
            }
            return true;
        }

        /// <summary>
        /// Проверка были ли изменены привязки к таблицам
        /// </summary>
        /// <returns>true - пользователь согласен продолжить без сохранения изменений либо изменений не было, 
        /// false - пользователь не согласен продолжать</returns>
        private bool CheckBindingChanged()
        {
            if (_bindingChanged)
            {
                if (GeneralMethods.ShowWarning(Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_ATTRIBUTE_BINDINGCHANGED, MessageBoxButtons.YesNo) == DialogResult.No)
                    return false;
            }
            return true;
        }

        /// <summary>
        /// Перестраивает таблицы привязок
        /// </summary>
        private void RefreshBindingTables()
        {
            if (!CheckBindingChanged())
                return;
            try
            {
                bool toBind = false;
                ClassificationStage stage = (ClassificationStage)(BindingBox.SelectedIndex + 1);
                switch (stage)
                {
                    case ClassificationStage.Training:                        
                        toBind = !ManualTrainingCheck.Checked;
                        break;
                    case ClassificationStage.Input:                        
                        toBind = !ManualInputCheck.Checked;
                        break;
                    case ClassificationStage.Output:                        
                        toBind = !ManualOutputCheck.Checked;
                        break;
                    default:
                        Assert.Fail(Assert.Id.Assert00325);
                        break;
                }
                if (!toBind)
                {
                    BindingGrid.Visible = false;
                    ApplyBindingButton.Visible = false;
                    BindingGrid.Rows.Clear();
                    NoBindingLabel.Visible = true;
                }
                else
                {
                    NoBindingLabel.Visible = false;
                    BindingGrid.Rows.Clear();
                    if (!CheckIndicators(true))
                        return;
                    DataGridViewRowCollection rows = BindingGrid.Rows;
                    OneOfManyFieldsGetter attributeFieldGetter = null;
                    OneFieldGetter classFieldGetter = null;
                    OneFieldGetter descriptionFieldGetter = null;
                    switch (stage)
                    {
                        case ClassificationStage.Training:                            
                            attributeFieldGetter = _problem.GetTrainingAttributeField;
                            classFieldGetter = _problem.GetTrainingClassField;
                            break;
                        case ClassificationStage.Input:                            
                            attributeFieldGetter = _problem.GetInputAttributeField;
                            descriptionFieldGetter = _problem.GetInputDescriptionField;
                            break;
                        case ClassificationStage.Output:                            
                            attributeFieldGetter = _problem.GetOutputAttributeField;
                            classFieldGetter = _problem.GetOutputClassField;
                            descriptionFieldGetter = _problem.GetOutputDescriptionField;
                            break;
                        default:
                            Assert.Fail(Assert.Id.Assert00323);
                            break;
                    }
                    if (descriptionFieldGetter != null)
                    {
                        TableField tableField = descriptionFieldGetter();
                        rows.Add();
                        DataGridViewRow row = rows[rows.Count - 1];
                        row.DefaultCellStyle.BackColor = SystemColors.Highlight;
                        row.Tag = BindingGridRowType.Description;
                        var textCell = row.Cells[0] as DataGridViewTextBoxCell;
                        textCell.Value = Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_DESCRIPTIONBINDING;
                        var tableCombo = row.Cells[1] as DataGridViewComboBoxCell;
                        FillTables(tableCombo);
                        tableCombo.Value = tableField == null ? Constants.NullNotDefinedString : _projectLink.RepositoryLink.GetObjectDescriptorById(tableField.TableId).ToString();
                        var fieldCombo = row.Cells[2] as DataGridViewComboBoxCell;
                        fieldCombo.Value = tableField == null ? Constants.NullNotDefinedString : tableField.FieldName;
                    }
                    if (classFieldGetter != null)
                    {
                        TableField tableField = classFieldGetter();
                        rows.Add();
                        DataGridViewRow row = rows[rows.Count - 1];
                        row.DefaultCellStyle.BackColor = SystemColors.Highlight;
                        row.Tag = BindingGridRowType.Class;
                        var textCell = row.Cells[0] as DataGridViewTextBoxCell;
                        textCell.Value = _problem.ClassesNames.ToString();
                        var tableCombo = row.Cells[1] as DataGridViewComboBoxCell;
                        FillTables(tableCombo);
                        tableCombo.Value = tableField == null ? Constants.NullNotDefinedString : _projectLink.RepositoryLink.GetObjectDescriptorById(tableField.TableId).ToString();
                        var fieldCombo = row.Cells[2] as DataGridViewComboBoxCell;
                        fieldCombo.Value = tableField == null ? Constants.NullNotDefinedString : tableField.FieldName;
                    }
                    IIndicator attributes = _problem.AttributesNames;
                    for (int i = 1; i < attributes.GetIndicatorValuesCount(); i++) //с первого, т.к. 0й - [не важно]
                    {
                        int attributeIndex = i - 1;
                        var tableField = attributeFieldGetter(attributeIndex);
                        rows.Add();
                        var row = rows[rows.Count - 1];
                        row.Tag = BindingGridRowType.Attribute;
                        var textCell = row.Cells[0] as DataGridViewTextBoxCell;
                        textCell.Value = attributes.GetIndicatorValueByPosition(i).Value as string;
                        var tableCombo = row.Cells[1] as DataGridViewComboBoxCell;
                        FillTables(tableCombo);
                        tableCombo.Value = tableField == null ? Constants.NullNotDefinedString : _projectLink.RepositoryLink.GetObjectDescriptorById(tableField.TableId).ToString();
                        var fieldCombo = row.Cells[2] as DataGridViewComboBoxCell;
                        fieldCombo.Value = tableField == null ? Constants.NullNotDefinedString : tableField.FieldName;
                    }
                    BindingGrid.Visible = true;
                    ApplyBindingButton.Visible = true;
                }
            }
            finally
            {
                _bindingChanged = false;
            }
        }

        /// <summary>
        /// Применяет изменения в привязках
        /// </summary>
        private void ApplyBinding()
        {
            var rows = BindingGrid.Rows;
            if (rows.Count == 0)
                return;
            ClassificationStage stage = (ClassificationStage)(BindingBox.SelectedIndex + 1);
            OneFieldSetter descriptionFieldSetter = null;
            OneFieldSetter classFieldSetter = null;
            OneOfManyFieldsSetter attributeFieldSetter = null;
            switch (stage)
            {
                case ClassificationStage.Training:                    
                    classFieldSetter = _problem.SetTrainingClassField;
                    attributeFieldSetter = _problem.SetTrainingAttributeField;                    
                    break;
                case ClassificationStage.Input:
                    descriptionFieldSetter = _problem.SetInputDescriptionField;                        
                    attributeFieldSetter = _problem.SetInputAttributeField;
                    break;
                case ClassificationStage.Output:
                    descriptionFieldSetter = _problem.SetOutputDescriptionField;
                    classFieldSetter = _problem.SetOutputClassField;
                    attributeFieldSetter = _problem.SetOutputAttributeField;
                    break;
                default:
                    Assert.Fail(Assert.Id.Assert00324);
                    break;
            }
            if (descriptionFieldSetter != null)
            {
                var row = rows[0];
                var tableCombo = row.Cells[1] as DataGridViewComboBoxCell;
                int tableIndex = tableCombo.Items.IndexOf(tableCombo.Value) - 1; //-1, т.к. первая строка "не выбрано"
                ITable table = null;
                if (tableIndex >= 0)
                    table = _tables[tableIndex].Bind() as ITable;
                var fieldCombo = row.Cells[2] as DataGridViewComboBoxCell;
                int fieldIndex = fieldCombo.Items.IndexOf(fieldCombo.Value) - 1; //-1, т.к. первая строка "не выбрано"
                string fieldName = fieldIndex == -1 ? string.Empty : fieldCombo.Value as string;
                descriptionFieldSetter(table, fieldName);
            }
            if (classFieldSetter != null)
            {
                var row = rows[0];
                var tableCombo = row.Cells[1] as DataGridViewComboBoxCell;
                int tableIndex = tableCombo.Items.IndexOf(tableCombo.Value) - 1; //-1, т.к. первая строка "не выбрано"
                ITable table = null;
                if (tableIndex >= 0)
                    table = _tables[tableIndex].Bind() as ITable;
                var fieldCombo = row.Cells[2] as DataGridViewComboBoxCell;
                int fieldIndex = fieldCombo.Items.IndexOf(fieldCombo.Value) - 1; //-1, т.к. первая строка "не выбрано"
                string fieldName = fieldIndex == -1 ? string.Empty : fieldCombo.Value as string;                                
                classFieldSetter(table, fieldName);
            }
            for (int i = (classFieldSetter == null ? 0 : 1); i < rows.Count; i++)
            {
                var row = rows[i];
                var tableCombo = row.Cells[1] as DataGridViewComboBoxCell;
                var tableIndex = tableCombo.Items.IndexOf(tableCombo.Value) - 1; //-1, т.к. первая строка "не выбрано"
                ITable table = null;
                if (tableIndex >= 0)
                    table = _tables[tableIndex].Bind() as ITable;
                var fieldCombo = row.Cells[2] as DataGridViewComboBoxCell;
                var fieldIndex = fieldCombo.Items.IndexOf(fieldCombo.Value) - 1; //-1, т.к. первая строка "не выбрано"
                var fieldName = fieldIndex == -1 ? string.Empty : fieldCombo.Value as string;
                attributeFieldSetter(stage == ClassificationStage.Input ?
                    i - 1 : //в вводе первая строка это строка пояснения
                    (stage == ClassificationStage.Training ?
                    i - 1 : //в обучении первая строка это строка класса
                    i - 2), //в выводе первая строка это строка пояснения, вторая строка это строка класса
                    table, fieldName);
            }
            _bindingChanged = false;
            RefreshBindingTables();
        }

        /// <summary>
        /// Обрабатывает смену имен признаков
        /// </summary>
        private void ProcessAttributesNamesChange()
        {
            if (_isInitialized)
            {
                int index = AttributesNamesBox.SelectedIndex;
                IIndicator indicator = index == 0 ? null : _indicators[index - 1].Bind() as IIndicator;
                try
                {
                    _problem.SetAttributesNames(indicator);
                }
                catch (BIClassificationProblemIndicatorNotDefinedException ex)
                {
                    GeneralMethods.ShowUserError(ex.Message);
                    return;
                }
                RefreshBindingTables();
            }
        }

        /// <summary>
        /// Отображает диалог задания параметров признаков
        /// </summary>
        private void ShowSetInfoDialog()
        {
            if ((_problem.Method == ClassificationProblemMethod.ModifiedClassificator) && (_problem.DistanceMethod == DistanceMethod.EstimatedEuclid))
            {
                SetClassificationProblemAttributesWeightsDialog weightsDialog = new SetClassificationProblemAttributesWeightsDialog(_problem);
                weightsDialog.ShowDialog();
                return;
            }
            if (_problem.Method == ClassificationProblemMethod.SimpleClassificator)
            {
                SetClassificationProblemAttributesGroupsAndDifferenceDialog groupsAndDifferenceDialog = new SetClassificationProblemAttributesGroupsAndDifferenceDialog(_problem);
                groupsAndDifferenceDialog.ShowDialog();
                return;
            }
            Assert.Fail(Assert.Id.Assert00308);//в остальных случаях кнопка вообще-то невидимой должна быть
        }

        /// <summary>
        /// Обрабатывает смену максимально допустимого расстояния между объектами
        /// </summary>
        /// <returns></returns>
        private bool ProcessEMaximumDifferenceChange()
        {
            double val = 0;
            bool parsed = double.TryParse(EMaximumDifferenceBox.Text, NumberStyles.Float, CultureInfo.CurrentUICulture, out val);
            if (parsed)
            {
                try
                {
                    _problem.SetEMaximumDifference(val);
                }
                catch (ArgumentOutOfRangeException)
                {
                    parsed = false;
                }
            }
            if (!parsed)
            {
                EMaximumDifferenceErrorProvider.SetError(EMaximumDifferenceBox, Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_EMAXIMUMDIFFERENCE_INCORRECTNUMBER);
                return false;
            }
            EMaximumDifferenceErrorProvider.SetError(EMaximumDifferenceBox, string.Empty);
            return true;
        }

        /// <summary>
        /// Обновляет возможность открытия выходных таблиц
        /// </summary>
        private void RefreshOpenOutputTableAbilities()
        {
            bool anySelected = OutputInTablesBox.SelectedItems.Count > 0;
            OutputInTablesOpenTableButton.Enabled = anySelected;
            открытьВыделенныеТаблицыToolStripMenuItem.Enabled = anySelected;
        }

        /// <summary>
        /// Открывает выделенные таблицы на вкладке "Результаты"
        /// </summary>
        private void OpenSelectedOutputTables()
        {
            foreach (ListViewItem item in OutputInTablesBox.SelectedItems)
            {
                _projectExplorer.OpenObject(item.Tag as IMetadataObjectDescriptor);
            }
        }

        /// <summary>
        /// Обрататывает смену активной вкладки
        /// </summary>
        /// <param name="page"></param>
        private void ProcessActiveTabChange(DevExpress.XtraTab.XtraTabPage page)
        {
            if (page == BindingsTab)
            {
                BindingBox.SelectedIndex = 0;
                return;
            }
            if (page == OutputTablesTab)
            {
                //обновляем список выходящих таблиц
                var items = OutputInTablesBox.Items;
                items.Clear();
                IMetadataObjectDescriptor outputClassTable = null;
                ListViewItem classItem = null;
                if (_problem.ClassesNames != null)
                {
                    TableField outputClassField = _problem.GetOutputClassField();
                    if (outputClassField != null)
                    {
                        outputClassTable = _projectLink.RepositoryLink.GetObjectDescriptorById(outputClassField.TableId);
                        classItem = items.Add(outputClassTable.Name);
                        classItem.SubItems.Add(outputClassTable.Label);
                        classItem.SubItems.Add(string.Format(Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_CLASSBINDING, _problem.ClassesNames.ToString()));
                        classItem.Tag = outputClassTable;
                    }
                }
                IIndicator attributes = _problem.AttributesNames;
                if (attributes != null)
                {
                    int attributesCount = attributes.GetIndicatorValuesCount() - 1;//минус 1, т.к. 0й - [не важно]
                    bool classBindExtended = false;
                    for (int i = 1; i <= attributesCount; i++)//с первого, т.к. 0й - [не важно]
                    {
                        int attributeIndex = i - 1;
                        string attributeName = attributes.GetIndicatorValueByPosition(i).Value as string;
                        TableField outputAttributeField = _problem.GetOutputAttributeField(attributeIndex);
                        if (outputAttributeField == null)
                            continue;
                        IMetadataObjectDescriptor outputAttributeTable = _projectLink.RepositoryLink.GetObjectDescriptorById(outputAttributeField.TableId);
                        ////проверяем, может надо к привязке класса дописать?
                        if ((outputClassTable != null) && (outputAttributeTable.Id == outputClassTable.Id))
                        {
                            var classBind = classItem.SubItems[2];
                            var classItemText = classBind.Text;
                            if (!classBindExtended)
                            {
                                classItemText = string.Format("{0}; {1}",
                                    classItemText,
                                    string.Format(Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_ATTRIBUTEBINDINGS,
                                    string.Format(Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_ATTRIBUTEBINDING, attributeName)));
                            }
                            else
                            {
                                classItemText = string.Format("{0}, {1}",
                                    classItemText,
                                    string.Format(Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_ATTRIBUTEBINDING, attributeName));
                            }
                            classBind.Text = classItemText;
                            classBindExtended = true;
                            continue;
                        }
                        ListViewItem attributeItem = null;
                        //проверяем, может надо к предыдущим привязкам признаков дописать?
                        for (int j = 1; j < items.Count; j++)
                        {
                            attributeItem = items[i];
                            IMetadataObjectDescriptor beforeOutputAttributeTable = attributeItem.Tag as IMetadataObjectDescriptor;
                            if (beforeOutputAttributeTable.Id == outputAttributeTable.Id)
                            {
                                //дописываем
                                var beforeBind = attributeItem.SubItems[2];
                                var attributeItemText = beforeBind.Text;
                                attributeItemText = string.Format("{0}, {1}",
                                    attributeItemText,
                                    string.Format(Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_ATTRIBUTEBINDING, attributeName));
                                beforeBind.Text = attributeItemText;
                                break;
                            }
                        }
                        //новая строка привязки признака!                                                        
                        attributeItem = items.Add(outputAttributeTable.Name);
                        attributeItem.SubItems.Add(outputAttributeTable.Label);
                        attributeItem.SubItems.Add(string.Format(Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_ATTRIBUTEBINDINGS,
                            string.Format(Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_ATTRIBUTEBINDING, attributeName)));
                        attributeItem.Tag = outputAttributeTable;
                    }
                }                                
                return;
            }
        }

        /// <summary>
        /// Обрабатывает смену страницы ручного вывода
        /// </summary>
        private void ProcessOutputPageChange()
        {            
            int page = 1;
            bool parsed = int.TryParse(bindingNavigatorPositionItem.Text, NumberStyles.Integer, CultureInfo.CurrentUICulture, out page);
            if (!parsed || (page < 1))
            {
                //пользователь видимо сам ввёл какую-то фигню, 
                //надо отправить его на первую страницу
                OutputMoveTo(1);
                return;
            }
            if (page > _outputInfo.Count)
            {
                OutputDescriptionBox.Visible = false;
                OutputGrid.Visible = false;
                OutputClassLabel.Visible = false;
                OutputClassBox.Visible = false;               
                OutputIsCorrectLabel.Visible = false;
                OutputRightButton.Visible = false;
                OutputWrongButton.Visible = false;
                CorrectClassLabel.Visible = false;
                return;
            }
            if (_outputPage == (page - 1))
                return; //не изменилась страница
            _outputPage = page - 1;//-1, т.к. внутренняя нумерация с нуля
            OutputDescriptionBox.Visible = true;
            OutputGrid.Visible = true;
            OutputClassLabel.Visible = true;
            OutputClassBox.Visible = true;
            OutputIsCorrectLabel.Visible = true;
            OutputRightButton.Visible = true;
            OutputWrongButton.Visible = true;            
            var info = _outputInfo[_outputPage];            
            var objectAttributes = info.ObjectInfo.Attributes;
            var attributes = _problem.AttributesNames;
            OutputDescriptionBox.Text = info.ObjectInfo.Description;
            var rows = OutputGrid.Rows;
            rows.Clear();
            for (int i = 1; i < attributes.GetIndicatorValuesCount(); i++)//с первого, т.к. 0й - [не важно]
            {
                int attributeIndex = i - 1;
                rows.Add();
                var row = rows[attributeIndex];
                var cells = row.Cells;
                string attributeName = attributes.GetIndicatorValueByPosition(i).Value as string;
                (cells[0] as DataGridViewTextBoxCell).Value = attributeName;
                string attributeValue = objectAttributes[attributeIndex] == Constants.NullDouble ?
                    string.Empty : objectAttributes[attributeIndex].ToString(CultureInfo.CurrentUICulture);
                (cells[1] as DataGridViewTextBoxCell).Value = attributeValue;
            }            
            int[] estimated = info.EstimatedClasses;
            int estimatedSum = 0;
            for (int i = 0; i < estimated.Length; i++)
            {
                estimatedSum += estimated[i];
            }
            int[] rangedClasses = new int[estimated.Length];
            for (int i = 0; i < rangedClasses.Length; i++)
            {
                rangedClasses[i] = i;
            }            
            //ранжируем классы по убыванию их вероятности
            for (int i = 1; i < estimated.Length; i++)
            {
                int j = i;
                while (estimated[j] > estimated[j - 1])
                {
                    int temp = estimated[j - 1];
                    estimated[j - 1] = estimated[j];
                    estimated[j] = temp;
                    temp = rangedClasses[j - 1];
                    rangedClasses[j - 1] = rangedClasses[j];
                    rangedClasses[j] = temp;
                    j--;
                    if (j == 0)
                        break;
                }
            }
            var items = OutputClassBox.Items;
            items.Clear();
            var classes = _problem.ClassesNames;
            for (int i = 0; i < rangedClasses.Length; i++)
            {
                double percent = estimatedSum == 0 ? 
                    ((double)1 / (double)rangedClasses.Length) 
                    : 
                    ((double)estimated[i] / (double)estimatedSum);
                string className = classes.GetIndicatorValueByPosition(rangedClasses[i] + 1).Value as string;//+1, т.к. в показателе первая строка - [не важно]
                items.Add(string.Format(Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_CLASSESTIMATED,
                    i + 1, className, (percent * 100).ToString("#0.00", CultureInfo.CurrentUICulture)));
            }
            OutputClassBox.SelectedIndex = 0;
            RefreshMarkCorrectAvailable();                        
        }

        /// <summary>
        /// Передвигается на указанную страницу вывода
        /// </summary>
        /// <param name="pageIndex"></param>
        private void OutputMoveTo(int pageIndex)
        {
            bindingNavigatorPositionItem.Text = (pageIndex).ToString(CultureInfo.CurrentUICulture);
        }

        /// <summary>
        /// Передвигается в указанном направлении вывода
        /// </summary>
        /// <param name="direction"></param>
        private void OutputMoveAside(Directions1D direction)
        {
            int page = direction == Directions1D.Back ? 2 : _outputInfo.Count - 1;
            int.TryParse(bindingNavigatorPositionItem.Text, NumberStyles.Integer, CultureInfo.CurrentUICulture, out page);
            page += direction == Directions1D.Back ? -1 : 1;
            if (page > _outputInfo.Count)
                page = _outputInfo.Count;
            if (page < 1)
                page = 1;            
            OutputMoveTo(page);                     
        }

        /// <summary>
        /// Обновляет доступность кнопок пометки объекта как верно/неверно классифицированного
        /// </summary>
        private void RefreshMarkCorrectAvailable()
        {
            int correctClass = _outputClassCorrect[_outputPage];
            bool available = correctClass == Constants.NullInteger;
            OutputRightButton.Enabled = available;
            OutputWrongButton.Enabled = available;
            CorrectClassLabel.Visible = !available;
            if (!available)
            {
                bool correct = correctClass == _outputInfo[_outputPage].Class;
                CorrectClassLabel.Text = correct ?
                    Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_CLASS_CORRECT :
                    Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_CLASS_INCORRECT;
                CorrectClassLabel.ForeColor = correct ? Color.Green : Color.Red;
            }            
        }

        /// <summary>
        /// Помечает текущую страницу ручного вывода как неверно классифицированную
        /// </summary>
        private void MarkAsWrongResult()
        {
            ClassificationProblemWithTrainingSetCorrectClassDialog setCorrectClassDialog = new ClassificationProblemWithTrainingSetCorrectClassDialog(_problem);
            if (setCorrectClassDialog.ShowDialog() == DialogResult.OK)
            {
                _outputClassCorrect[_outputPage] = setCorrectClassDialog.CorrectClass;
                setCorrectClassDialog.Dispose();
                setCorrectClassDialog = null;
                var info = _outputInfo[_outputPage].ObjectInfo;
                _problem.Train(info.Attributes, _outputClassCorrect[_outputPage], false);
                RefreshTrainingCount();
                RefreshMarkCorrectAvailable();
            }
        }

        /// <summary>
        /// Помечает текущую страницу ручного вывода как правильно классифицированную
        /// </summary>
        private void MarkAsRightResult()
        {
            var info = _outputInfo[_outputPage].ObjectInfo;
            _outputClassCorrect[_outputPage] = info.Class;
            _problem.Train(info.Attributes, info.Class, false);
            RefreshTrainingCount();
            RefreshMarkCorrectAvailable();            
        }

        /// <summary>
        /// Строит матрицу классификации
        /// </summary>
        private void BuildClassificationMatrix()
        {
            //собираем информацию о правильности классификации
            int haveCorrectInfo = 0;
            for (int i = 0; i < _outputClassCorrect.Count; i++)
            {
                if (_outputClassCorrect[i] != Constants.NullInteger)
                {
                    haveCorrectInfo++;                    
                }                
            }
            if (haveCorrectInfo == 0)
            {
                GeneralMethods.ShowUserError(Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_CLASSIFICATIONMATRIX_NOCORRECTINFO);
                return;
            }
            ClassificationQualityInfo qualityInfo = null;
            try
            {
                qualityInfo = _problem.CalculateClassificationQuality(_outputClassCorrect.ToArray());
            }
            catch (BIClassificationProblemNotSolvedException ex)
            {
                GeneralMethods.ShowUserError(ex.Message);
                return;
            }
            if (haveCorrectInfo != _outputClassCorrect.Count)
                GeneralMethods.ShowInformation(string.Format(Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_CLASSIFICATIONMATRIX_LITTLECORRECTINFO, haveCorrectInfo, _outputClassCorrect.Count));
            ClassificationMatrixDialog matrixDialog = new ClassificationMatrixDialog(_problem, qualityInfo, _projectExplorer);
            matrixDialog.ShowDialog();            
        }

        /// <summary>
        /// Экспортирует входные-выходные данные в новую таблицу
        /// </summary>
        /// <param name="outputs"></param>
        private void ExportInputsOutputs(bool outputs)
        {
            List<ClassificationObjectInfo> infos = new List<ClassificationObjectInfo>();
            for (int i = 0; i < _outputInfo.Count; i++)
            {
                infos.Add(_outputInfo[i].ObjectInfo);
            }
            ClassificationProblemWithTrainingExporter exporter = new ClassificationProblemWithTrainingExporter(_problem, _projectLink.RepositoryLink);
            ITable table = null;
            try
            {
                table = exporter.ExportToTable(infos, outputs);
            }
            catch (BIDataTransferException ex)
            {
                GeneralMethods.ShowUserError(ex.Message);
                return;
            }
            if (table != null)//бывает равен null если transfer в точку назначения провалился
                _projectExplorer.OpenObject(table);
        }

        /// <summary>
        /// Конструктор класса
        /// </summary>
        public ClassificationProblemWithTrainingRunDialog(ProjectExplorerForm projectExplorer, IClassificationProblemWithTraining problem)
        {
            _projectExplorer = projectExplorer;
            _projectLink = projectExplorer.ProjectLink;
            _problem = problem;
            InitializeComponent();
        }        

        private void CalculationRunDialog_Load(object sender, EventArgs e)
        {
            Initialize();
        }        

        private void MethodBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            ProcessMethodChange();
        }

        private void DistanceMethodBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            ProcessDistanceMethodChange();
        }

        private void TrainButton_Click(object sender, EventArgs e)
        {
            Train();
        }

        private void RunButton_Click(object sender, EventArgs e)
        {
            Execute();            
        }

        private void ManualTrainingCheck_CheckedChanged(object sender, EventArgs e)
        {
            ProcessManualTrainingChange();
        }

        private void ManualInputCheck_CheckedChanged(object sender, EventArgs e)
        {
            ProcessManualInputChange();
        }

        private void ManualOutputCheck_CheckedChanged(object sender, EventArgs e)
        {
            ProcessManualOutputChange();
        }

        private void ClassesNamesBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            ProcessClassesNamesChange();
        }

        private void AttributesNamesBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            ProcessAttributesNamesChange();
        }

        private void BindingBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            RefreshBindingTables();
        }

        private void BindingGrid_CellValueChanged(object sender, DataGridViewCellEventArgs e)
        {
            ProcessBindingGridCellValueChange(e.RowIndex, e.ColumnIndex);
        }

        private void ApplyBindingButton_Click(object sender, EventArgs e)
        {
            ApplyBinding();
        }

        private void SetInfoButton_Click(object sender, EventArgs e)
        {
            ShowSetInfoDialog();
        }

        private void ClassificationTabs_SelectedPageChanged(object sender, DevExpress.XtraTab.TabPageChangedEventArgs e)
        {
            ProcessActiveTabChange(e.Page);
        }

        private void EMaximumDifferenceBox_Validating(object sender, CancelEventArgs e)
        {
            e.Cancel = !ProcessEMaximumDifferenceChange();
        }        

        private void открытьВыделенныеТаблицыToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenSelectedOutputTables();
        }

        private void bindingNavigatorMoveFirstItem_Click(object sender, EventArgs e)
        {
            OutputMoveTo(1);
        }

        private void bindingNavigatorMoveLastItem_Click(object sender, EventArgs e)
        {
            OutputMoveTo(_outputInfo.Count);            
        }

        private void bindingNavigatorMovePreviousItem_Click(object sender, EventArgs e)
        {
            OutputMoveAside(Directions1D.Back);           
        }

        private void bindingNavigatorMoveNextItem_Click(object sender, EventArgs e)
        {
            OutputMoveAside(Directions1D.Forward);
        }

        private void bindingNavigatorPositionItem_TextChanged(object sender, EventArgs e)
        {
            ProcessOutputPageChange();
        }

        private void OutputWrongButton_Click(object sender, EventArgs e)
        {
            MarkAsWrongResult();
        }

        private void OutputRightButton_Click(object sender, EventArgs e)
        {
            MarkAsRightResult();
        }

        private void OutputInTablesBox_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
        {
            RefreshOpenOutputTableAbilities();
        }

        private void OutputInTablesBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
                OpenSelectedOutputTables();        
        }

        private void OutputInTablesOpenTableButton_Click(object sender, EventArgs e)
        {
            OpenSelectedOutputTables();
        }

        private void EditTrainButton_Click(object sender, EventArgs e)
        {
            EditTrain();            
        }

        private void BuildClassificationMatrixButton_Click(object sender, EventArgs e)
        {
            BuildClassificationMatrix();
        }

        private void OutputInTablesContext_Opening(object sender, CancelEventArgs e)
        {
            RefreshOpenOutputTableAbilities();
        }

        private void ClassificationProblemWithTrainingRunDialog_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = !CheckBindingChanged();
        }

        private void толькоЗначенияПризнаковToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ExportInputsOutputs(false);
        }

        private void значенияПризнаковИКлассыToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ExportInputsOutputs(true);
        }  
    }

    /// <summary>
    /// Тип строки грида привязок
    /// </summary>
    internal enum BindingGridRowType
    {
        /// <summary>
        /// Не установлен
        /// </summary>
        None = 0,
        /// <summary>
        /// Признак
        /// </summary>
        Attribute = 1,
        /// <summary>
        /// Класс
        /// </summary>
        Class = 2,
        /// <summary>
        /// Описание
        /// </summary>
        Description = 3
    }
}
